﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Xml;
using System.IO;
using System.Text;

namespace MobileAPI.Web.Data
{
    /// <summary>
    /// 通信的 Xml 数据
    /// </summary>
    public class MobileXml
    {
        public const string RootNodeName = "Message";
        public const string HeadNodeName = "Head";
        public const string BodyNodeName = "Body";

        /// <summary>
        /// 报文的 Head
        /// </summary>
        public HeadField Head
        {
            get;
            protected set;
        }

        /// <summary>
        /// 报文的 Body
        /// </summary>
        public BodyField Body
        {
            get;
            protected set;
        }

        public MobileXml()
        {
            this.Head = new HeadField();
            this.Body = new BodyField();
        }

        public MobileXml(string xml)
            : this()
        {
            FromXml(xml);
        }

        public void FromXml(string xml)
        {
            // 清空
            this.Head.Clear();
            this.Body.Clear();

            // 加载
            XmlDocument doc = new XmlDocument();
            doc.LoadXml(xml);

            // Head
            XmlNode node = doc.SelectSingleNode("/" + RootNodeName + "/" + HeadNodeName);
            if (node == null)
            {
                throw new XmlException("MobileXml 格式错误，缺少节点 Head");
            }
            this.Head.FromXml(node);

            // Body
            node = doc.SelectSingleNode("/" + RootNodeName + "/" + BodyNodeName);
            if (node == null)
            {
                throw new XmlException("MobileXml 格式错误，缺少节点 Body");
            }
            this.Body.FromXml(node);
        }

        public string ToXml()
        {
            using (MemoryStream ms = new MemoryStream())
            {
                XmlWriterSettings settings = new XmlWriterSettings();
                settings.Encoding = new UTF8Encoding(false);
                settings.Indent = true;
                settings.NewLineChars = Environment.NewLine;
                using (XmlWriter xw = XmlWriter.Create(ms, settings))
                {
                    xw.WriteStartDocument();
                    xw.WriteStartElement(RootNodeName);
                    this.Head.ToXml(xw);
                    this.Body.ToXml(xw);
                    xw.WriteEndElement();
                    xw.WriteEndDocument();
                    xw.Flush();
                    xw.Close();
                }
                return Encoding.UTF8.GetString(ms.ToArray());
            }
        }

        /// <summary>
        /// 报文的 Head
        /// </summary>
        public class HeadField : FieldList
        {
            public HeadField()
            {
                this.Name = MobileXml.HeadNodeName;
            }
        }

        /// <summary>
        /// 报文的 Body
        /// </summary>
        public class BodyField : FieldList
        {
            public BodyField()
            {
                this.Name = MobileXml.BodyNodeName;
            }
        }

        /// <summary>
        /// 报文的 Field
        /// </summary>
        public class Field : BaseField
        {
            public Field(string name, string value)
            {
                this.Name = name;
                this.Value = value;
            }

            internal Field(XmlNode node)
            {
                FromXml(node);
            }

            public override void Clear()
            {

            }

            public override void FromXml(XmlNode node)
            {
                this.Name = node.Name;
                this.Value = node.InnerText;
                foreach (XmlAttribute attr in node.Attributes)
                {
                    this.Attributes.Add(attr.Name, attr.Value);
                }
            }

            public override void ToXml(XmlWriter xw)
            {
                xw.WriteStartElement(this.Name);

                if (this.Attributes.Count > 0)
                {
                    foreach (KeyValuePair<string, string> kv in this.Attributes)
                    {
                        xw.WriteAttributeString(kv.Key, kv.Value);
                    }
                }

                xw.WriteValue(this.Value ?? string.Empty);
                xw.WriteEndElement();
            }
        }

        /// <summary>
        /// 报文的 FieldList
        /// </summary>
        public class FieldList : BaseField
        {
            protected List<BaseField> _childs;

            /// <summary>
            /// 所有的孩子，包括 Field FieldList
            /// </summary>
            public BaseField[] Childs
            {
                get
                {
                    return _childs.ToArray();
                }
            }

            /// <summary>
            /// 所有的 Field 值
            /// </summary>
            public Field[] Fields
            {
                get
                {
                    List<Field> fields = new List<Field>();
                    foreach (var item in _childs)
                    {
                        if (item is Field)
                        {
                            fields.Add((Field)item);
                        }
                    }
                    return fields.ToArray();
                }
            }

            /// <summary>
            /// 所有的 FieldList 值
            /// </summary>
            public FieldList[] FieldLists
            {
                get
                {
                    List<FieldList> fieldLists = new List<FieldList>();
                    foreach (var item in _childs)
                    {
                        if (item is FieldList)
                        {
                            fieldLists.Add((FieldList)item);
                        }
                    }
                    return fieldLists.ToArray();
                }
            }

            public FieldList()
            {
                _childs = new List<BaseField>();
            }

            public FieldList(string name)
                : this()
            {
                this.Name = name;
            }

            internal FieldList(XmlNode node)
                : this()
            {
                FromXml(node);
            }

            /// <summary>
            /// 根据索引获取 FieldList
            /// </summary>
            /// <param name="index"></param>
            /// <returns></returns>
            public FieldList GetFieldList(int index)
            {
                FieldList[] array = this.FieldLists;
                if (array != null && index < array.Length)
                {
                    return array[index];
                }
                else
                {
                    return null;
                }
            }

            /// <summary>
            /// 获取第一个 FieldList
            /// </summary>
            /// <returns></returns>
            public FieldList GetFirstFieldList()
            {
                return GetFieldList(0);
            }

            /// <summary>
            /// 根据名称获取 Field 或 FieldList
            /// </summary>
            /// <param name="name"></param>
            /// <returns></returns>
            public BaseField GetChild(string name)
            {
                foreach (var item in _childs)
                {
                    if (item.Name == name)
                    {
                        return item;
                    }
                }
                return null;
            }

            /// <summary>
            /// 根据名称获取 Field 或 FieldList
            /// </summary>
            /// <param name="name"></param>
            /// <returns></returns>
            public BaseField[] GetChilds(string name)
            {
                List<BaseField> list = new List<BaseField>();
                foreach (var item in _childs)
                {
                    if (item.Name == name)
                    {
                        list.Add(item);
                    }
                }
                return list.ToArray();
            }

            /// <summary>
            /// 根据名称获取 FieldList
            /// </summary>
            /// <param name="name"></param>
            /// <returns></returns>
            public FieldList GetFieldList(string name)
            {
                foreach (var item in _childs)
                {
                    if (item is FieldList && item.Name == name)
                    {
                        return (FieldList)item;
                    }
                }
                return null;
            }

            /// <summary>
            /// 根据名称获取 FieldLists
            /// </summary>
            /// <param name="name"></param>
            /// <returns></returns>
            public FieldList[] GetFieldLists(string name)
            {
                List<FieldList> fieldLists = new List<FieldList>();
                foreach (var item in _childs)
                {
                    if (item is FieldList && item.Name == name)
                    {
                        fieldLists.Add((FieldList)item);
                    }
                }
                return fieldLists.ToArray();
            }

            /// <summary>
            /// 根据 Field 名获取 Field
            /// </summary>
            /// <param name="fieldName"></param>
            /// <returns></returns>
            public Field GetField(string fieldName)
            {
                foreach (var item in _childs)
                {
                    if (item is Field && item.Name == fieldName)
                    {
                        return (Field)item;
                    }
                }
                return null;
            }

            /// <summary>
            /// 根据 Field 名获取 Field
            /// </summary>
            /// <param name="fieldName"></param>
            /// <returns></returns>
            public Field[] GetFields(string fieldName)
            {
                List<Field> fields = new List<Field>();
                foreach (var item in _childs)
                {
                    if (item is Field && item.Name == fieldName)
                    {
                        fields.Add((Field)item);
                    }
                }
                return fields.ToArray();
            }

            /// <summary>
            /// 根据 Field 名获取其值
            /// </summary>
            /// <param name="fieldName"></param>
            /// <returns></returns>
            public string GetFieldValue(string fieldName)
            {
                Field f = GetField(fieldName);
                if (f != null)
                {
                    return f.Value;
                }
                else
                {
                    return null;
                }
            }

            /// <summary>
            /// 根据 Field 名获取其值
            /// </summary>
            /// <param name="fieldName"></param>
            /// <returns></returns>
            public int GetFieldInt32(string fieldName)
            {
                Field f = GetField(fieldName);
                if (f != null)
                {
                    return string.IsNullOrEmpty(f.Value) ? 0 : Convert.ToInt32(f.Value.Trim());
                }
                else
                {
                    return 0;
                }
            }

            /// <summary>
            /// 根据 Field 名获取其值
            /// </summary>
            /// <param name="fieldName"></param>
            /// <returns></returns>
            public long GetFieldInt64(string fieldName)
            {
                Field f = GetField(fieldName);
                if (f != null)
                {
                    return string.IsNullOrEmpty(f.Value) ? 0 : Convert.ToInt64(f.Value.Trim());
                }
                else
                {
                    return 0;
                }
            }

            /// <summary>
            /// 根据 Field 名获取其值
            /// </summary>
            /// <param name="fieldName"></param>
            /// <returns></returns>
            public double GetFieldDouble(string fieldName)
            {
                Field f = GetField(fieldName);
                if (f != null)
                {
                    return string.IsNullOrEmpty(f.Value) ? 0 : Convert.ToDouble(f.Value.Trim());
                }
                else
                {
                    return 0;
                }
            }

            /// <summary>
            /// 加入 Field
            /// </summary>
            /// <param name="name"></param>
            /// <param name="value"></param>
            /// <returns></returns>
            public Field AddField(string name, string value)
            {
                return AddField(new Field(name, value));
            }

            /// <summary>
            /// 加入 Field
            /// </summary>
            /// <param name="field"></param>
            /// <returns></returns>
            internal Field AddField(Field field)
            {
                if (field != null)
                {
                    field.Owner = this;

                    // 添加
                    _childs.Add(field);
                }
                return field;
            }

            /// <summary>
            /// 加入 FieldList
            /// </summary>
            /// <param name="name"></param>
            /// <returns></returns>
            public FieldList AddFieldList(string name)
            {
                return AddFieldList(new FieldList(name));
            }

            /// <summary>
            /// 加入 FieldList
            /// </summary>
            /// <param name="fl"></param>
            /// <returns></returns>
            public FieldList AddFieldList(FieldList fl)
            {
                if (fl != null)
                {
                    fl.Owner = this;

                    // 添加
                    _childs.Add(fl);
                }
                return fl;
            }

            /// <summary>
            /// 加入 Child
            /// </summary>
            /// <param name="name"></param>
            /// <param name="value"></param>
            /// <returns></returns>
            public BaseField AddChild(BaseField bf)
            {
                if (bf == null)
                {
                    return null;
                }

                if (bf is MobileXml.Field)
                {
                    return AddField((MobileXml.Field)bf);
                }
                else if (bf is MobileXml.FieldList)
                {
                    return AddFieldList((MobileXml.FieldList)bf);
                }

                return null;
            }

            /// <summary>
            /// 根据名称移除 Field
            /// </summary>
            /// <param name="name"></param>
            public void RemoveField(string name)
            {
                MobileXml.Field f = GetField(name);
                if (f != null)
                {
                    _childs.Remove(f);
                }
            }

            /// <summary>
            /// 根据名称移除 FieldList
            /// </summary>
            /// <param name="name"></param>
            public void RemoveFieldList(string name)
            {
                MobileXml.FieldList fl = GetFieldList(name);
                if (fl != null)
                {
                    _childs.Remove(fl);
                }
            }

            /// <summary>
            /// 清空
            /// </summary>
            public override void Clear()
            {
                foreach (BaseField f in this.Childs)
                {
                    f.Clear();
                }
                _childs.Clear();
            }

            public override void FromXml(XmlNode node)
            {
                // 子节点总数
                int childCount = 0;

                // 节点属性集
                this.Name = node.Name;
                foreach (XmlAttribute attr in node.Attributes)
                {
                    this.Attributes.Add(attr.Name, attr.Value);
                }

                // 子节点
                foreach (XmlNode childNode in node.ChildNodes)
                {
                    if (childNode.NodeType == XmlNodeType.Element)
                    {
                        if (HasChildNodes(childNode))
                        {
                            AddFieldList(new FieldList(childNode));
                        }
                        else
                        {
                            AddField(new Field(childNode));
                        }
                        childCount++;
                    }
                }

                // 无子节点
                if (childCount == 0)
                {
                    this.Value = node.InnerText;
                }
            }

            public override void ToXml(XmlWriter xw)
            {
                // 自身节点开始
                xw.WriteStartElement(this.Name);

                // 自定义属性
                if (this.Attributes.Count > 0)
                {
                    foreach (KeyValuePair<string, string> kv in this.Attributes)
                    {
                        xw.WriteAttributeString(kv.Key, kv.Value);
                    }
                }

                // 值为空
                if (string.IsNullOrEmpty(this.Value))
                {
                    // 子元素
                    foreach (BaseField item in this.Childs)
                    {
                        item.ToXml(xw);
                    }
                }
                else
                {
                    xw.WriteValue(this.Value ?? string.Empty);
                }

                // 自身节点结束
                xw.WriteEndElement();
            }

            /// <summary>
            /// 检查节点是否有子节点
            /// </summary>
            /// <param name="node"></param>
            /// <returns></returns>
            private bool HasChildNodes(XmlNode node)
            {
                int childCount = 0;
                foreach (XmlNode childNode in node.ChildNodes)
                {
                    if (childNode.NodeType == XmlNodeType.Element)
                    {
                        childCount++;
                        if (childCount > 0)
                        {
                            return true;
                        }
                    }
                }
                return false;
            }
        }

        /// <summary>
        /// Field FieldList 基类
        /// </summary>
        public abstract class BaseField
        {
            /// <summary>
            /// 存放扩展属性
            /// </summary>
            protected Dictionary<string, string> _attributes;

            public BaseField Owner { get; set; }
            public string Name { get; set; }
            public string Value { get; set; }
            public object Tag { get; set; }

            /// <summary>
            /// 扩展属性
            /// </summary>
            public Dictionary<string, string> Attributes
            {
                get
                {
                    if (_attributes == null)
                    {
                        _attributes = new Dictionary<string, string>();
                    }
                    return _attributes;
                }
            }

            public abstract void Clear();
            public abstract void FromXml(XmlNode node);
            public abstract void ToXml(XmlWriter xw);
        }
    }
}